
"""
*******************友情提示：使用脚本前请仔细阅读以下内容************

python脚本运行环境要求：
*1、此脚本针对WatchHousingButton上传开发的功能,目前只支持HTTP上传。
*2、此文件名，调用接口需要配置在FilterPythonScript中进行配置，
*3、此脚本运行环境为Python3.7.1，安装Python环境必须添加到环境变量中，具体安装请查阅SOP
*4、非开发人员请勿更改核心部分，请注意不能修改的地方

python脚本功能：
[1]WatchHousingButton数据上传脚本
[2]上传逻辑;先进行报站请求，报站成功后，执行数据上传，反之数据上传失败！如果报站结果返回的是False，直接返回给logic，并通知plc夹出该产品
[3]脚本需要两个配置文件：processControlConfig.xml(报站信息的配置) watchHousingConfig.xml（数据上传信息的配置） 注：后期优化可合并


错误提示：
*1、配置内容错误，则无法完成上传，可通过查看D:/IVLogs下查看脚本运行日志，排查错误
*2、修改配置之后如无法加载到对应的脚本文件，则修改出现问题，可通过已安装的python运行程序，排查错误。
*3、修改出现错误不要慌，紧紧按住CTRL+Z，回到它原本的样子。


版本号：
V1.0.1

v1.0.0
更新内容
[1]设置接口函数为user_func，测试完成。
[2]增加输出日志，方便排查问题

v1.0.1
更新内容
[1]:增加读取processControlConfig.xml文件的函数 ReadProcessXML()。
[2]:增加processControlConfig.xml 配置文件，可配置多个请求路径和返回信息，目前支持两个上传参数
[3]:增加处理报站请求的函数ProcessControl()，如请求失败，则无法上传数据
[4]:增加Get请求的数据访问方式的函数，ProcessControlRequest()

"""
import logging
import sys
import datetime
from xml.dom.minidom import parse
import http.client
import json
import ast
import os

#版本号配置
version = "V1.0.1"
#当前脚本对应的数据类型
dataType="HttpUploadData"
"""
配置1：上传数据信息的参数配置
"""
head_id = "3"
line_id = "1"
fixture_id = "xxxxxxxxxxxxxxxx"
machine_id = "1"
station_id = "xxxxxxxxxxxxxxxxxxxxxxx"
software_name = "WatchTest"
software_version = "V1.1"
Site_LineID_MachineID_StationName=line_id+machine_id


"""
配置2：xml配置文件对应上传参数标识
"""
testDataConfig = "1"  #测试数据上传参数标识对应配置文件中 number


#日志环境配置
"""
配置3：日志路径的配置
"""
logging.basicConfig(format='%(asctime)s | %(pathname)s | line:%(lineno)d | %(levelname)s | %(message)s',
					level=logging.DEBUG, filemode='a',
					filename='D:\\IVLogs\\' + datetime.datetime.now().strftime('%Y%m%d') + '_PY.log')
rf_handler = logging.StreamHandler(sys.stderr)
rf_handler.setLevel(logging.DEBUG)
rf_handler.setFormatter(logging.Formatter('%(asctime)s | %(pathname)s | line:%(lineno)d | %(levelname)s | %(message)s'))
logging.getLogger().addHandler(rf_handler)





#以下部分为代码核心部分，
# Before I wrote it, only God and I knew what I was doing. Now only God knows
"""
函数功能：判断当前工作目录中是否存在两个配置文件
"""
def ConfigExist():
    currentWorkPath=os.getcwd()
    logging.info("当前工作目录为:" + currentWorkPath)
    if(not os.path.exists("watchHousingConfig.xml")):
        logging.error(currentWorkPath+"中不存在watchHousingConfig.xml文件，请检查")
        return False
    return True

"""
函数功能;实现上传配置文件的调用
"""
def ReadXML():
    try:
        domTree = parse("watchHousingConfig.xml")
        rootNode = domTree.documentElement
        # 所有信息
        customers = rootNode.getElementsByTagName("watchingHousingButton")
        list1=[]
        for customer in customers:
            tempList = []
            if customer.hasAttribute("number"):
                number = customer.getAttribute("number")
                httpUrl =customer.getElementsByTagName("httpUrl")[0]
                httpPort =customer.getElementsByTagName("httpPort")[0]
                httpFiles = customer.getElementsByTagName("httpFiles")[0]
                httpHeadder = customer.getElementsByTagName("httpHeadder")[0]

                tempList.append(number)
                tempList.append(httpUrl.childNodes[0].data)
                tempList.append(httpPort.childNodes[0].data)
                tempList.append(httpFiles.childNodes[0].data)
                tempList.append(httpHeadder.childNodes[0].data)
            list1.append(tempList)
        return list1
    except Exception as e:
        print("无法加载配置文件:configuration.xml")
        print(e)
        return []

'''
函数功能：实现上传
'''
def DataUpload(url, headers, productData, files,port):
    """
    实现数据的上传，并回馈结果
    """
    try:
        logging.info("开始连接网络:%s......."%url)
        if port == 0:
            conn = http.client.HTTPConnection(url)
        else:
            conn = http.client.HTTPConnection(url,port)
        conn.request("POST",files,productData,headers)
        res = conn.getresponse()
        data = res.read()
        logging.info("请求成功response：%s"%data.decode("utf-8"))
        return f'\"{data.decode("utf-8")}\"'
    except Exception as e:
        logging.info("网络连接失败：%s,请检查网络设置"%url)
        logging.info("Exception:%s"%e)
        return "Connect Fail"

"""
****外部调用入口函数******
函数功能：提供给模块调用的接口，请勿更改函数名称
in_data: 外部传入需上传的数据
parameter： 预留参数,类型为string，目前传递值为“1”如需要修改，可通过FilterPythonScript模块开发使用。
"""
def user_func_http_upload(in_data,parameter):
    try:
        logging.info("当前执行版本为：%s"%version)
        return "1111"
        if (not ConfigExist()): return
        deal_data = json.loads(in_data)
        if dataType==deal_data["dataType"]:
            if in_data.find("sn") >= 0:
              response = DealUploadInfo(deal_data["data"])
              logging.info("HttpUpload执行结束，返回结果："+response)
              return response
            else:
              logging.info("当前上传格式未知，请检查上传格式")
              return '{"returnType": "HttpUploadData", "sn": "null", "result":"Script Fail"}'
        else:
            logging.info(f"当前传入数据的数据种类={deal_data['dataType']}不是该脚本{dataType}对应的处理类型，故忽略")
            return '{"returnType": "ProcessControl", "sn": "null", "result":"Ignore"}'
    except Exception as e:
        logging.info("user_func函数执行失败，请检查！！"%e)

"""
函数功能：处理上传逻辑
"""
def DealUploadInfo(in_data):
    logging.info("开始解析需要上传的信息")
    try:
        #目前设计过程只有一次上传，其他上传格式暂不清楚
        uploadData = GetUploadFormat(in_data)
        # if uploadData["Testresult"].find("fail") >= 0:
        #     logging.info("上传数据格式设置错误，无法正确上传")
        #     return "fail"
        logging.info("数据格式获取成功，准备上传！上传信息《%s》"%uploadData)
        #实现测试数据HTTP上传
        response= UploadTestData(uploadData)
        return response
    except Exception as e:
        logging.error("数据转换为JSON异常！Exception：%s"%e)
        return "uploadFail"

"""
函数功能：设置上传的数据格式
"""
def GetUploadFormat(deal_data):
    try:
        logging.info("开始构造上传的数据结构")
        binResult = "Bin"+str(deal_data["bin"])
        logging.info("binResult设置结束《%s》"%binResult)
        uploadDataJson={
            "serials":{
                "wip_id":deal_data["sn"]
            },
            "data":{
                "insight": {
                    "results": [{
                        "test": "Color_L_Star",
                        "value": deal_data["DL"],
                        "result": deal_data["colorLResult"],
                        "lower_limit": deal_data["DL_lower"],
                        "upper_limit": deal_data["DL_upper"]
                    }, {
                        "test": "Color_A_Star",
                        "value": deal_data["DA"],
                        "result": deal_data["colorAResult"],
                        "lower_limit": deal_data["DA_lower"],
                        "upper_limit": deal_data["DA_upper"]
                    }, {
                        "test": "Color_B_Star",
                        "value": deal_data["DB"],
                        "result": deal_data["colorBResult"],
                        "lower_limit": deal_data["DB_lower"],
                        "upper_limit": deal_data["DB_upper"]
                    }, {
                        "test": "Color_Delta_E94",
                        "value": deal_data["E94"],
                        "result": deal_data["E94Result"],
                        "lower_limit": deal_data["E94_lower"],
                        "upper_limit": deal_data["E94_upper"]
                    }, {
                        "test": "Gloss_GU",
                        "value": deal_data["gloss"],
                        "result": deal_data["glossResult"],
                        "lower_limit": deal_data["Gloss_lower"],
                        "upper_limit": deal_data["Gloss_upper"]
                    }],
                    "uut_attributes": {
                        "bin": deal_data["bin"],
                        "Dot_SN": "DotCode2",
                        "Trace_SN": deal_data["sn"]
                    },
                    "test_attributes": {
                        "uut_stop": deal_data["uut_stop"],
                        "uut_start": deal_data["uut_start"],
                        "test_result": deal_data["productResult"],
                        "unit_serial_number": "F9F204202FF12M02R"
                    },
                    "test_station_attributes": {
                        "head_id": head_id,
                        "line_id": line_id,
                        "fixture_id": fixture_id,
                        "machine_id": machine_id,
                        "station_id": station_id,
                        "Site_LineID_MachineID_StationName": Site_LineID_MachineID_StationName,
                        "software_name": software_name,
                        "software_version": software_version
                    }},
                "properties": {
                    "Bin": binResult
                }
            },
            "event":deal_data["productResult"]
        }
        logging.info("数据上传格式设置结束！")
        return json.dumps(uploadDataJson)
    except Exception as e:
        logging.info("数据转换为JSON异常！Exception：%s"%e)
        uploadDataJson={
            "Testresult":"fail"
        }
        return uploadDataJson

"""
函数功能：上传测试数据
"""
def UploadTestData(uploadData):
    sn=json.loads(uploadData)["serials"]["wip_id"]
    try:
        logging.info("开启测试数据上传")
        #1、读取配置文件中对应的参数信息
        configInfo = ReadConfigInfo(testDataConfig)
        #2、开始数据上传
        if len(configInfo) >= 5:
            url = configInfo[1]
            headers =ast.literal_eval(configInfo[4].replace("\n", ""))
            files = configInfo[3]
            if configInfo[2].isspace ():
                port = 0
            else :
                port = int(configInfo[2])
            uploadResult = DataUpload(url=url,headers=headers,productData=uploadData,files=files,port=port)
        else:
            logging.error("配置文件无法获取有效信息，请检查配置文件")
            uploadResult="Script Fail"
        return '{"returnType": "HttpUploadData", "sn": "' + sn +'", "result": '+uploadResult+'}'
    except Exception as e:
        logging.error("上传测试函数执行失败，请检查上传信息")
        return '{"returnType": "HttpUploadData", "sn": "' + sn +'", "result":"Script Fail"}'

"""
函数功能:读取对应的配置参数
"""
def ReadConfigInfo(logo):
    readResult = 0
    configInfo =[]
    configInfoList = ReadXML()
    for list in configInfoList:
        for number in list:
            if number == logo:
                logging.info("读取配置信息成功")
                readResult =1
                break
            else:
                logging.error("未找到对应的配置信息，请检查配置文件")
        if readResult == 1:
            configInfo = list
            break
    return configInfo

#测试区域
#test_data=r'{"dataType":"HttpUploadData","data":{"DA":"-12.000000","DA_lower":0.0,"DA_upper":3.0,"DB":"-12.000000","DB_lower":0.0,"DB_upper":3.0,"DL":"-12.000000","DL_lower":0.0,"DL_upper":3.0,"E94":"0.000000","E94Result":"pass","E94_lower":0.0,"E94_upper":1.0,"Gloss_lower":12.0,"Gloss_upper":15.0,"bin":0,"colorA":"0.000000","colorAResult":"fail","colorB":"0.000000","colorBResult":"fail","colorL":"0.000000","colorLResult":"fail","gloss":"0.000000","glossResult":"fail","productResult":"fail","sn":"1572","uut_start":"2022-04-16 13:39:41","uut_stop":"2022-04-16 13:39:24"}}'
#test_data=r'{"dataType":"SNProcessControl","data":{"sn":"1572"}}'
#print(user_func_http_upload(test_data,0))
#ReadXML()
#ReadConfigInfo(testDataConfig)
#UploadTestData("1")
#ReadProcessXML()
#ProcessControl()
